using System;
using System.Collections.Generic;
using System.Text;
using SqlTools.CodeGenerator.Data;
using System.Data;
using System.IO;

namespace SqlTools.CodeGenerator.CSharp
{
	public class BusinessObjectGenerator
	{
		protected Table _table;

		public BusinessObjectGenerator(Table table)
		{
			_table = table;
		}

		public void CreateBusinessObject()
		{
			CodeBuilder cb = new CodeBuilder(_table.BusinessNamespace, _table.BusinessObjectName);
			cb.PartialClass = true;


			GenerateUsingStatements(cb);
			cb.NewLine();

			if ( _table.BaseTable != null )
			{
				cb.Bases.Add(_table.BaseTable.BusinessObjectName);
			}
			else
			{
				cb.Bases.Add("BusinessObject");
			}
			cb.Bases.Add("IDbObject<" + _table.PrimaryKeyClassName + ">");

			GenerateFields(cb);
			cb.NewLine();

			GenerateConstructor(cb);
			cb.NewLine();

			GenerateIDbObject(cb);

			foreach ( TableProperty prop in _table.Properties )
			{
				switch ( prop.Type )
				{
					case TablePropertyType.Intrinsic:
						IntrinsicTableProperty itp = prop as IntrinsicTableProperty;

						if ( itp.BaseClassPK )
							continue;

						GenerateProperty(cb, prop);

						if ( itp.ForeignKeys.Count > 0 )
						{
							foreach ( ForeignKeyTableProperty fktp in itp.ForeignKeys )
							{
								GenerateChildForeignKeyProperty(cb, fktp);
							}
						}
						break;
					case TablePropertyType.ForeignKey:
						ForeignKeyTableProperty fkprop = prop as ForeignKeyTableProperty;

						GenerateParentForeignKeyProperty(cb, fkprop);

						if ( fkprop.ForeignKeys.Count > 0 )
						{
							foreach ( ForeignKeyTableProperty fktp in fkprop.ForeignKeys )
							{
								GenerateChildForeignKeyProperty(cb, fktp);
							}
						}


						break;
					case TablePropertyType.PrimaryKey:
						PrimaryKeyTableProperty pktp = prop as PrimaryKeyTableProperty;
						foreach ( TableProperty tp in pktp.Properties )
						{
							if ( tp.ForeignKeys.Count > 0 )
							{
								foreach ( ForeignKeyTableProperty fktp in tp.ForeignKeys )
								{
									GenerateChildForeignKeyProperty(cb, fktp);
								}
							}

							if ( tp.Type == TablePropertyType.ForeignKey )
							{
								ForeignKeyTableProperty fktp = tp as ForeignKeyTableProperty;

								GenerateParentForeignKeyProperty(cb, fktp);
							}
						}
						break;
				}

				cb.NewLine();
			}

			CreateUpdate(cb);
			cb.NewLine();

			CreateInsert(cb);
			cb.NewLine();

			CreateDelete(cb);
			cb.NewLine();

			CreateCreateDbObject(cb);
			cb.NewLine();

			CreateCreateFromReader(cb);
			cb.NewLine();

			CreateFillFromReader(cb);
			cb.NewLine();

			CreateLoad(cb);

			string fileText = cb.GetText();

			string fileName = Path.Combine(_table.Project.RootDirectory, _table.BusinessDirectory);

			Directory.CreateDirectory(fileName);

			string file = _table.BusinessObjectName;
			if ( _table.Project.UseGeneratedPartialClassFormat )
				file += ".generated";

			file += ".cs";

			fileName = Path.Combine(fileName, file);

			StreamWriter sw = File.CreateText(fileName);
			sw.Write(fileText);
			sw.Close();

			if ( _table.Project.UseGeneratedPartialClassFormat )
			{
				// create edittable partial class

				fileName = Path.Combine(_table.Project.RootDirectory, _table.BusinessDirectory);

				file = _table.BusinessObjectName;

				file += ".cs";

				fileName = Path.Combine(fileName, file);

				// check to see if file exists.  If it does, we do nothing

				if ( !File.Exists(fileName) )
				{

					cb = new CodeBuilder(_table.BusinessNamespace, _table.BusinessObjectName);
					cb.PartialClass = true;

					GenerateUsingStatements(cb);

					fileText = cb.GetText();

					sw = File.CreateText(fileName);
					sw.Write(fileText);
					sw.Close();
				}

			}

		}

		protected void GenerateUsingStatements(CodeBuilder cb)
		{
			cb.Namespaces.Add("System");
			cb.Namespaces.Add("System.Collections.Generic");
			cb.Namespaces.Add("System.Text");
			// check for xml
			bool hasXml = false;

			_table.Properties.OperateOnProperties(delegate(TableProperty prop)
			{
				if ( prop.DataType == SqlDbType.Xml )
					hasXml = true;
			}
			);

			if ( hasXml )
				cb.Namespaces.Add("System.Xml");

			cb.Namespaces.Add("SqlTools.DataAccessLibrary");
			cb.Namespaces.Add(_table.DataNamespace);
			cb.Namespaces.Add("System.Data");
		}

		protected void GenerateFields(CodeBuilder cb)
		{
            //TODOS GPC
            if (_table.Properties.Count == 0) return;
			cb.AppendField(_table.PrimaryKeyClassName, _table.PrimaryKeyFieldName);
			foreach ( TableProperty prop in _table.Properties )
			{
				if ( prop.Type != TablePropertyType.PrimaryKey )
				{
					if ( prop.Type == TablePropertyType.ForeignKey )
					{
						ForeignKeyTableProperty fkprop = prop as ForeignKeyTableProperty;

						cb.AppendField(prop.CSharpDataType, fkprop.FieldName);
						cb.AppendField(fkprop.ReferenceTable.BusinessObjectName, fkprop.ReferenceObjectFieldName);
					}
					else
					{
						if ( prop.Type == TablePropertyType.Intrinsic && ( (IntrinsicTableProperty)prop ).BaseClassPK )
							continue;

						cb.AppendField(prop.CSharpDataType, prop.FieldName);
						// check for reference foreign keys
						if ( prop.ForeignKeys.Count > 0 )
						{
							// add child references
							foreach ( ForeignKeyTableProperty fktp in prop.ForeignKeys )
							{
								cb.AppendField("DbList<" + fktp.ForeignKeyTable.BusinessObjectName + ">", fktp.ForeignObjectFieldName);
							}
						}
					}
				}
				else
				{
					// check for reference foreign keys
					PrimaryKeyTableProperty pktp = prop as PrimaryKeyTableProperty;

					foreach ( TableProperty tp in pktp.Properties )
					{

						if ( tp.ForeignKeys.Count > 0 )
						{
							// add child references
							foreach ( ForeignKeyTableProperty fktp in tp.ForeignKeys )
							{
								cb.AppendField("DbList<" + fktp.ForeignKeyTable.BusinessObjectName + ">", fktp.ForeignObjectFieldName);
							}
						}

						if ( tp.Type == TablePropertyType.ForeignKey )
						{
							ForeignKeyTableProperty fkprop = tp as ForeignKeyTableProperty;

                            if (fkprop.ForeignKeyTable == null)
                                return;
							cb.AppendField(fkprop.ReferenceTable.BusinessObjectName, fkprop.ReferenceObjectFieldName);
						}
					}
				}
			}
		}

		protected void GenerateConstructor(CodeBuilder cb)
		{
			cb.BeginConstructor();

			cb.Append(_table.PrimaryKeyFieldName).Append(" = new ").Append(_table.PrimaryKeyClassName).Append("()").NewLine(true);

			foreach ( TableProperty prop in _table.Properties )
			{
				if ( prop.Type != TablePropertyType.PrimaryKey )
				{
					if ( prop.Type == TablePropertyType.Intrinsic && ( (IntrinsicTableProperty)prop ).BaseClassPK )
						continue;

					if ( prop.Type == TablePropertyType.ForeignKey )
					{
						ForeignKeyTableProperty fkprop = prop as ForeignKeyTableProperty;

						cb.Append(fkprop.ReferenceFieldName).Append(" = ").Append(fkprop.DefaultValue).NewLine(true);
						cb.Append(fkprop.ReferenceObjectFieldName).Append(" = ").Append("null").NewLine(true);
					}
					else
					{
						cb.Append(prop.FieldName).Append(" = ").Append(prop.DefaultValue).NewLine(true);
					}

					// check for foreign keys

					if ( prop.ForeignKeys.Count > 0 )
					{
						// add child references
						foreach ( ForeignKeyTableProperty fktp in prop.ForeignKeys )
						{
							cb.Append(fktp.ForeignObjectFieldName).Append(" = ").Append("null").NewLine(true);
						}
					}
				}
				else
				{
					// check for reference foreign keys
					PrimaryKeyTableProperty pktp = prop as PrimaryKeyTableProperty;

					foreach ( TableProperty tp in pktp.Properties )
					{
						if ( tp.ForeignKeys.Count > 0 )
						{
							// add child references
							foreach ( ForeignKeyTableProperty fktp in tp.ForeignKeys )
							{
								cb.Append(fktp.ForeignObjectFieldName).Append(" = ").Append("null").NewLine(true);
							}
						}

						if ( tp.Type == TablePropertyType.ForeignKey )
						{
							ForeignKeyTableProperty fkprop = tp as ForeignKeyTableProperty;

							cb.Append(fkprop.ReferenceObjectFieldName).Append(" = ").Append("null").NewLine(true);
						}
					}
				}
			}

			cb.EndConstructor();
		}

		protected void GenerateIDbObject(CodeBuilder cb)
		{
			cb.BeginRegion("IDbObject<" + _table.PrimaryKeyClassName + "> Members");
			cb.NewLine();

			OverloadType overload = ( _table.BaseTable != null ? OverloadType.New : OverloadType.None );

			cb.BeginProperty(AccessibilityLevel.Public, _table.PrimaryKeyClassName, "Key", overload);
			cb.AppendGet(_table.PrimaryKeyFieldName);
			cb.EndProperty();

			cb.NewLine();
			cb.EndRegion();
		}

		protected void GenerateProperty(CodeBuilder cb, TableProperty prop)
		{
			cb.BeginProperty(prop.CSharpDataType, prop.PropertyName);

			cb.AppendGet(prop.FieldName);

			cb.BeginSet();
			cb.Append(prop.FieldName).Append(" = value").NewLine(true);
			cb.Append("_UpdateState()").NewLine(true);
			cb.EndSet();

			cb.EndProperty();
		}

		protected void GenerateChildForeignKeyProperty(CodeBuilder cb, ForeignKeyTableProperty fkprop)
		{
			string dbObject = NamingHelper.ClassVariableName(fkprop.ForeignKeyTable.DbObjectName);
			cb.BeginProperty("DbList<" + fkprop.ForeignKeyTable.BusinessObjectName + "> ", fkprop.ForeignObjectPropertyName);

			cb.BeginGet();
			cb.Append("if ( ").Append(fkprop.ForeignObjectFieldName).Append(" == null )").NewLine();
			cb.BeginBlock();

			cb.Append(fkprop.ForeignKeyTable.DbObjectName).Append(" ").Append(dbObject).NewLine(true);

			cb.Append("if ( !string.IsNullOrEmpty(_ConnectionStringName) )").NewLine();
			cb.SingleLineIndent().Append(dbObject).Append(" = new ").Append(fkprop.ForeignKeyTable.DbObjectName).Append("(_ConnectionStringName)").NewLine(true);
			cb.Append("else").NewLine();
			cb.SingleLineIndent().Append(dbObject).Append(" = new ").Append(fkprop.ForeignKeyTable.DbObjectName).Append("()").NewLine(true);
			cb.NewLine();
			cb.Append(fkprop.ForeignObjectFieldName).Append(" = ").Append(dbObject).Append(".").Append(fkprop.ForeignRetrieve.MethodName).Append("(");
			// pass in parameters to the retrieve method
			bool first = true;
			foreach ( MethodParameter param in fkprop.ForeignRetrieve.Parameters )
			{
				if ( !first )
				{
					cb.Append(", ");
				}
				else
				{
					first = false;
				}
				// find the property on remote object
				ForeignKeyTableProperty fktp = null;
				foreach ( TableProperty prop in fkprop.ForeignKeyTable.Properties )
				{
					if ( prop.Type == TablePropertyType.PrimaryKey )
					{
						PrimaryKeyTableProperty pkprop = prop as PrimaryKeyTableProperty;

						foreach ( TableProperty subprop in pkprop.Properties )
						{
							if ( subprop.Type != TablePropertyType.ForeignKey )
								continue;

							ForeignKeyTableProperty fksubprop = subprop as ForeignKeyTableProperty;

							if ( fksubprop.ForeignKeyColumnName == param.Property.ColumnName )
							{
								fktp = fksubprop;
								break;
							}
						}
					}
					else if ( prop.Type == TablePropertyType.ForeignKey )
					{
						ForeignKeyTableProperty fksubprop = prop as ForeignKeyTableProperty;

						if ( fksubprop.ForeignKeyColumnName == param.Property.ColumnName )
						{
							fktp = fksubprop;
						}
					}

					if ( fktp != null )
						break;
				}

				// find parameter on this object
				if ( fktp != null )
				{
					bool found = false;
					foreach ( TableProperty tp in fktp.ReferenceTable.Properties )
					{
						if ( tp.Type == TablePropertyType.PrimaryKey )
						{
							PrimaryKeyTableProperty pktp = tp as PrimaryKeyTableProperty;

							foreach ( TableProperty stp in pktp.Properties )
							{
								if ( stp.ColumnName == fktp.ReferenceColumnName )
								{
									cb.Append("this.Key.").Append(stp.PropertyName);
									found = true;
									break;
								}
							}
						}
						else
						{
							if ( tp.ColumnName == fktp.ReferenceColumnName )
							{
								cb.Append("this.").Append(tp.PropertyName);
								found = true;
							}
						}

						if ( found )
							break;
					}
				}
			}
			cb.Append(")").NewLine(true);
			// ------------------------------------
			cb.NewLine();
			cb.Append(fkprop.ForeignObjectFieldName).Append(".ItemAdded += new DbListItemAdded<").Append(fkprop.ForeignKeyTable.BusinessObjectName).Append(">(").Append(fkprop.ForeignObjectFieldName).Append("_ItemAdded)").NewLine(true);
			cb.Append(fkprop.ForeignObjectFieldName).Append(".ItemChanged += new DbListItemChanged<").Append(fkprop.ForeignKeyTable.BusinessObjectName).Append(">(").Append(fkprop.ForeignObjectFieldName).Append("_ItemChanged)").NewLine(true);
			cb.Append(fkprop.ForeignObjectFieldName).Append(".ItemRemoved += new DbListItemRemoved<").Append(fkprop.ForeignKeyTable.BusinessObjectName).Append(">(").Append(fkprop.ForeignObjectFieldName).Append("_ItemRemoved)").NewLine(true);
			cb.EndBlock();

			cb.Append("return ").Append(fkprop.ForeignObjectFieldName).NewLine(true);
			cb.EndGet();
			cb.EndProperty();

			cb.NewLine();

			GenerateItemAddedEventHandler(cb, fkprop);
			cb.NewLine();
			GenerateItemChangedEventHandler(cb, fkprop);
			cb.NewLine();
			GenerateItemRemovedEventHandler(cb, fkprop);
			cb.NewLine();
		}

		protected void GenerateParentForeignKeyProperty(CodeBuilder cb, ForeignKeyTableProperty fkprop)
		{
            //TODOS GPC
            if (fkprop.ReferenceTable == null) return;
            if (fkprop.ForeignKeyTable == null) return;

			string refFieldName = "";

			bool isRefPk = false;

			if ( !_table.IsPrimaryKeyProperty(fkprop) )
			{
				cb.BeginProperty(AccessibilityLevel.Public, fkprop.CSharpDataType, fkprop.ReferencePropertyName);
				cb.AppendGet(fkprop.ReferenceFieldName);
				cb.EndProperty();
				cb.NewLine();

				refFieldName = fkprop.ReferenceFieldName;
			}
			else
			{
				refFieldName = "this.Key." + fkprop.ReferencePropertyName;
			}

			PrimaryKeyTableProperty refPK = fkprop.ReferenceTable.GetPrimaryKey();

			if ( refPK != null )
			{
				TableProperty ttp = refPK.Properties.FindPropertyByColumnName(fkprop.ReferenceColumnName);

				isRefPk = ( ttp != null );
			}

			string dbObject = NamingHelper.ClassVariableName(fkprop.ReferenceTable.DbObjectName);
			cb.BeginProperty(fkprop.ReferenceTable.BusinessObjectName, fkprop.ReferenceObjectPropertyName);
			cb.BeginGet();

			cb.Append("if ( ").Append(fkprop.ReferenceObjectFieldName).Append(" == null && ").Append(refFieldName).Append(" != ").Append(fkprop.DefaultValue).Append(" )").NewLine();
			cb.BeginBlock();
			cb.Append(fkprop.ReferenceTable.DbObjectName).Append(" ").Append(dbObject).NewLine(true);

			cb.Append("if ( !string.IsNullOrEmpty(_ConnectionStringName) )").NewLine();
			cb.SingleLineIndent().Append(dbObject).Append(" = new ").Append(fkprop.ReferenceTable.DbObjectName).Append("(_ConnectionStringName)").NewLine(true);
			cb.Append("else").NewLine();
			cb.SingleLineIndent().Append(dbObject).Append(" = new ").Append(fkprop.ReferenceTable.DbObjectName).Append("()").NewLine(true);
			cb.NewLine();

			cb.Append(fkprop.ReferenceObjectFieldName).Append(" = ").Append(dbObject).Append(".").Append(fkprop.ReferenceRetrieve.MethodName).Append("(");

			if ( isRefPk )
			{
				cb.Append("new ");
				cb.Append(fkprop.ReferenceTable.PrimaryKeyClassName).Append("(").Append(refFieldName).Append(")");

			}
			else
			{
				cb.Append(refFieldName);
			}

			cb.Append(")").NewLine(true);

			cb.EndBlock();
			cb.Append("return ").Append(fkprop.ReferenceObjectFieldName).NewLine(true);
			cb.EndGet();

			cb.BeginSet();
			cb.Append("if ( ").Append(fkprop.ReferenceObjectFieldName).Append(" != value )").NewLine();
			cb.BeginBlock();

			cb.Append(fkprop.ReferenceObjectFieldName).Append(" = value").NewLine(true);
			cb.NewLine();
			cb.Append("if ( ").Append(fkprop.ReferenceObjectFieldName).Append(" != null )").NewLine();

			cb.BeginBlock();
			cb.Append(refFieldName).Append(" = ").Append(fkprop.ReferenceObjectFieldName);

			if ( isRefPk )
				cb.Append(".Key");

			cb.Append(".").Append(fkprop.ReferenceTable.Properties.FindPropertyByColumnName(fkprop.ReferenceColumnName).PropertyName).NewLine(true);
			cb.Append(fkprop.ReferenceObjectFieldName).Append(".Inserted += delegate(object sender, BusinessObjectEventArgs e)").NewLine();

			cb.BeginBlock();
			cb.Append("if ( e.Item != null )").NewLine();

			cb.BeginBlock();
			cb.Append(refFieldName).Append(" = ( (").Append(fkprop.ReferenceTable.BusinessObjectName).Append(")e.Item )");

			if ( isRefPk )
				cb.Append(".Key");

			cb.Append(".").Append(fkprop.ReferenceTable.Properties.FindPropertyByColumnName(fkprop.ReferenceColumnName).PropertyName).NewLine(true);
			cb.EndBlock();

			// custom endblock for anonymous delegate
			cb.Outdent().Append("}").NewLine(true);

			cb.EndBlock();
			cb.Append("else").NewLine();

			cb.BeginBlock();
			cb.Append(refFieldName).Append(" = ").Append(fkprop.DefaultValue).NewLine(true);
			cb.EndBlock();

			cb.NewLine();
			cb.Append("_UpdateState()").NewLine(true);
			cb.EndBlock();
			cb.EndSet();
			cb.EndProperty();
		}

		private void GenerateItemAddedEventHandler(CodeBuilder cb, ForeignKeyTableProperty fkprop)
		{
			Dictionary<string, string> parms = new Dictionary<string, string>();
			parms.Add("object", "sender");
			parms.Add("DbListItemAddedEventArgs<" + fkprop.ForeignKeyTable.BusinessObjectName + ">", "e");

			cb.BeginMethod(AccessibilityLevel.Protected, "void", fkprop.ForeignObjectFieldName + "_ItemAdded", parms);

			cb.Append("if ( e.ItemAdded != null )").NewLine();
			cb.BeginBlock();
			cb.Append("e.ItemAdded.").Append(fkprop.ReferenceObjectPropertyName).Append(" = this").NewLine(true);
			cb.EndBlock();

			cb.EndMethod();
		}

		private void GenerateItemChangedEventHandler(CodeBuilder cb, ForeignKeyTableProperty fkprop)
		{
			Dictionary<string, string> parms = new Dictionary<string, string>();
			parms.Add("object", "sender");
			parms.Add("DbListItemChangedEventArgs<" + fkprop.ForeignKeyTable.BusinessObjectName + ">", "e");

			cb.BeginMethod(AccessibilityLevel.Protected, "void", fkprop.ForeignObjectFieldName + "_ItemChanged", parms);

			cb.Append("if ( e.PreviousItem != null && e.PreviousItem.").Append(fkprop.ReferenceObjectPropertyName).Append(" == this )").NewLine();
			cb.BeginBlock();
			cb.Append("e.PreviousItem.").Append(fkprop.ReferenceObjectPropertyName).Append(" = null").NewLine(true);
			cb.EndBlock();
			cb.NewLine();

			cb.Append("if ( e.NewItem != null )").NewLine();
			cb.BeginBlock();
			cb.Append("e.NewItem.").Append(fkprop.ReferenceObjectPropertyName).Append(" = this").NewLine(true);
			cb.EndBlock();

			cb.EndMethod();
		}

		private void GenerateItemRemovedEventHandler(CodeBuilder cb, ForeignKeyTableProperty fkprop)
		{
			Dictionary<string, string> parms = new Dictionary<string, string>();
			parms.Add("object", "sender");
			parms.Add("DbListItemRemovedEventArgs<" + fkprop.ForeignKeyTable.BusinessObjectName + ">", "e");

			cb.BeginMethod(AccessibilityLevel.Protected, "void", fkprop.ForeignObjectFieldName + "_ItemRemoved", parms);

			cb.Append("if ( e.Item != null )").NewLine();
			cb.BeginBlock();
			cb.Append("e.Item.").Append(fkprop.ReferenceObjectPropertyName).Append(" = null").NewLine(true);
			cb.EndBlock();

			cb.EndMethod();
		}

		private void CreateUpdate(CodeBuilder cb)
		{
			string dbObject = NamingHelper.ClassVariableName(_table.DbObjectName);
			cb.BeginMethod(AccessibilityLevel.Public, "void", "Update", null, OverloadType.Override);

			// check for items with only PK params
			if ( _table.Properties.Count == 1 && _table.Properties[0].Type == TablePropertyType.PrimaryKey )
			{
				// should throw an exception when updating this
				cb.Append("throw new NotSupportedException(\"The ").Append(_table.BusinessObjectName).Append(" object can not be updated; only inserted or deleted\")").NewLine(true);
			}
			else
			{
				cb.Append("OnUpdating(this)").NewLine(true);
				cb.NewLine();
				cb.Append(_table.DbObjectName).Append(" ").Append(dbObject).Append(" = Create").Append(_table.DbObjectName).Append("()").NewLine(true);
				cb.Append(dbObject).Append(".Update(this)").NewLine(true);
				cb.NewLine();
				cb.Append("OnUpdated(this)").NewLine(true);
			}

			cb.EndMethod();
		}

		private void CreateInsert(CodeBuilder cb)
		{
			string dbObject = NamingHelper.ClassVariableName(_table.DbObjectName);
			cb.BeginMethod(AccessibilityLevel.Public, "void", "Insert", null, OverloadType.Override);

			cb.Append("OnInserting(this)").NewLine(true);
			cb.NewLine();
			cb.Append(_table.DbObjectName).Append(" ").Append(dbObject).Append(" = Create").Append(_table.DbObjectName).Append("()").NewLine(true);
			cb.Append(dbObject).Append(".Insert(this)").NewLine(true);
			cb.NewLine();
			cb.Append("OnInserted(this)").NewLine(true);

			cb.EndMethod();
		}

		private void CreateDelete(CodeBuilder cb)
		{
			string dbObject = NamingHelper.ClassVariableName(_table.DbObjectName);

			cb.BeginMethod(AccessibilityLevel.Public, "void", "Delete", null, OverloadType.Override);

			cb.Append("OnDeleting(this)").NewLine(true);
			cb.NewLine();
			cb.Append(_table.DbObjectName).Append(" ").Append(dbObject).Append(" = Create").Append(_table.DbObjectName).Append("()").NewLine(true);
			cb.Append(dbObject).Append(".Delete(this)").NewLine(true);
			cb.NewLine();
			cb.Append("OnDeleted(this)").NewLine(true);

			cb.EndMethod();
		}

		private void CreateCreateDbObject(CodeBuilder cb)
		{
			cb.BeginMethod(AccessibilityLevel.Protected, _table.DbObjectName, "Create" + _table.DbObjectName);

			cb.Append("if ( !string.IsNullOrEmpty(_ConnectionStringName) )").NewLine();
			cb.SingleLineIndent().Append("return new ").Append(_table.DbObjectName).Append("(_ConnectionStringName)").NewLine(true);
			cb.Append("else").NewLine();
			cb.SingleLineIndent().Append("return new ").Append(_table.DbObjectName).Append("()").NewLine(true);

			cb.EndMethod();
		}

		private void CreateCreateFromReader(CodeBuilder cb)
		{
			string objName = NamingHelper.ClassVariableName(_table.BusinessObjectName);

			OverloadType overload = ( _table.BaseTable != null ? OverloadType.New : OverloadType.None );
			Dictionary<string, string> parms = new Dictionary<string, string>();
			parms.Add("IDataReader", "reader");

			cb.BeginMethod(AccessibilityLevel.Public, _table.BusinessObjectName, "CreateFromReader", parms, overload, true);

			cb.Append(_table.BusinessObjectName).Append(" ").Append(objName).Append(" = new ").Append(_table.BusinessObjectName).Append("()").NewLine(true);
			cb.NewLine();
			cb.Append("FillFromReader(").Append(objName).Append(", reader)").NewLine(true);
			cb.NewLine();
			cb.Append("return ").Append(objName).NewLine(true);

			cb.EndMethod();
		}

		private void CreateFillFromReader(CodeBuilder cb)
		{
			string objName = NamingHelper.ClassVariableName(_table.BusinessObjectName);
			Dictionary<string, string> parms = new Dictionary<string, string>();
			parms.Add(_table.BusinessObjectName, objName);
			parms.Add("IDataReader", "reader");

			cb.BeginMethod(AccessibilityLevel.Public, "void", "FillFromReader", parms, OverloadType.None, true);

			cb.Append(objName).Append(".OnLoading(").Append(objName).Append(")").NewLine(true);
			cb.NewLine();

			foreach ( TableProperty prop in _table.Properties )
			{
				if ( prop.Type == TablePropertyType.PrimaryKey )
				{
					PrimaryKeyTableProperty pktp = prop as PrimaryKeyTableProperty;

					foreach ( TableProperty pkprop in pktp.Properties )
					{
						cb.Append(objName).Append(".Key.").Append(pkprop.PropertyName).Append(" = ");
						if ( pkprop.CSharpDataType != "string" )
							cb.Append("(").Append(pkprop.CSharpDataType).Append(")reader[\"").Append(pkprop.ColumnName).Append("\"]").NewLine(true);
						else
							cb.Append("reader[\"").Append(pkprop.ColumnName).Append("\"].ToString()").NewLine(true);
					}

					// now do base table primary key
					if ( _table.BaseTable != null )
					{
						PrimaryKeyTableProperty pkprop = _table.BaseTable.GetPrimaryKey();
						if ( pkprop != null )
						{
							foreach ( TableProperty bpkprop in pkprop.Properties )
							{
								cb.Append(objName).Append(".Key.").Append(bpkprop.PropertyName).Append(" = ");
								if ( bpkprop.CSharpDataType != "string" )
									cb.Append("(").Append(bpkprop.CSharpDataType).Append(")reader[\"").Append(bpkprop.ColumnName).Append("\"]").NewLine(true);
								else
									cb.Append("reader[\"").Append(bpkprop.ColumnName).Append("\"].ToString()").NewLine(true);
							}
						}
					}

				}
				else
				{
					if ( prop.Type == TablePropertyType.Intrinsic && ( (IntrinsicTableProperty)prop ).BaseClassPK )
						continue;

					if ( prop.Nullable )
					{
						cb.Append("if ( reader[\"").Append(prop.ColumnName).Append("\"] != DBNull.Value )").NewLine();
						cb.SingleLineIndent();
					}

					cb.Append(objName).Append(".").Append(prop.FieldName).Append(" = ");
					if ( prop.CSharpDataType != "string" )
						cb.Append("(").Append(prop.CSharpDataType).Append(")reader[\"").Append(prop.ColumnName).Append("\"]").NewLine(true);
					else
						cb.Append("reader[\"").Append(prop.ColumnName).Append("\"].ToString()").NewLine(true);
				}
			}

			cb.NewLine();

			cb.Append(objName).Append("._UpdateState(ObjectState.None)").NewLine(true);
			cb.NewLine();

			cb.Append(objName).Append(".OnLoaded(").Append(objName).Append(")").NewLine(true);

			cb.EndMethod();
		}

		private void CreateLoad(CodeBuilder cb)
		{
			string dbObject = NamingHelper.ClassVariableName(_table.DbObjectName);

			// first create overload without the connName
			Dictionary<string, string> parms = new Dictionary<string, string>();
			parms.Add(_table.PrimaryKeyClassName, "key");

			cb.BeginMethod(AccessibilityLevel.Public, _table.BusinessObjectName, "Load", parms, OverloadType.None, true);

			cb.Append("return Load(null, key)").NewLine(true);

			cb.EndMethod();

			cb.NewLine();
			// now create real load method
			parms = new Dictionary<string, string>();
			parms.Add("string", "connName");
			parms.Add(_table.PrimaryKeyClassName, "key");

			cb.BeginMethod(AccessibilityLevel.Public, _table.BusinessObjectName, "Load", parms, OverloadType.None, true);

			cb.Append(_table.DbObjectName).Append(" ").Append(dbObject).NewLine(true);
			cb.NewLine();

			cb.Append("if ( string.IsNullOrEmpty(connName) )").NewLine();
			cb.BeginBlock();

			cb.Append(dbObject).Append(" = new ").Append(_table.DbObjectName).Append("()").NewLine(true);

			cb.EndBlock();
			cb.Append("else").NewLine();
			cb.BeginBlock();

			cb.Append(dbObject).Append(" = new ").Append(_table.DbObjectName).Append("(connName)").NewLine(true);

			cb.EndBlock();
			cb.NewLine();

			cb.Append("return ").Append(dbObject).Append(".SelectByPK(key)").NewLine(true);

			cb.EndMethod();

		}
	}
}
